using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using Space;
using Space.Resources;
using Space.Planets;
using Space.Users;

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
    #region Constants

    public const int MaxPlanetPerStar = 12;
    public const int MinPlanetPerStar = 2;
    public const int MaxResourcePerPlanet = 3;
    public const int MinResourcePerPlanet = 1;

    public const int ResourceAmount = 10000;

    #endregion

    #region Static

    #region Test

    public bool IsSpaceInitialised_()
    {
        return (null != stars && stars.Count > 0);
    }

    #endregion

    #region Space

    //Dimenzije svemira
    private static int MaxX = 0;
    private static int MaxY = 0;
    private static int MaxZ = 0;

    // Lista koordinata zvezda
    private static Dictionary<string, Coordinate> starCoordinates = null;

    // Indeks koordinata zvezda
    private static Dictionary<int, Dictionary<int, Dictionary<int, Coordinate>>> starCoordinateIndex = null;

    //Lista zvezda
    private static List<Star> stars = null;
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    // Metoda koja kreira koordinate zvezda
    public static void CreateStarCoordinates(int maxX, int maxY, int maxZ, int count)
    {
        // Odredjivanje dimenzija svemira
        MaxX = maxX;
        MaxY = maxY;
        MaxZ = maxZ;

        starCoordinates = new Dictionary<string, Coordinate>();

        int x, y, z, x1, y1, z1;
        string key = "";
        string key1 = "";
        Random r = new Random(DateTime.Now.Millisecond);

        Coordinate c = null;

        for (int i = 0; i < count; i++)
        {
            x = r.Next(0, maxX);
            y = r.Next(0, maxY);
            z = r.Next(0, maxZ);

            key = x.ToString() + ";" + y.ToString() + ";" + z.ToString();

            if (!starCoordinates.ContainsKey(key))
            {
                starCoordinates.Add(key, new Coordinate(x, y, z));
            }
            else
            {
                do
                {
                    x1 = r.Next(0, maxX);
                    y1 = r.Next(0, maxY);
                    z1 = r.Next(0, maxZ);
                    key1 = x1.ToString() + ";" + y1.ToString() + ";" + z1.ToString();
                } while (starCoordinates.ContainsKey(key1));

                starCoordinates.Add(key1, new Coordinate());
            }
        }
    }

    // Metoda koja kreira indeks koordinata
    public static void CreateStarCoordinateIndex()
    {
        if (null != starCoordinates && starCoordinates.Count > 0)
        {
            starCoordinateIndex = new Dictionary<int, Dictionary<int, Dictionary<int, Coordinate>>>();

            Dictionary<int, Dictionary<int, Coordinate>> yCoordinates = null;
            Dictionary<int, Coordinate> zCoordinates = null;

            foreach(Coordinate c in starCoordinates.Values)
            {
                if (!starCoordinateIndex.ContainsKey(c.X))
                {
                    yCoordinates = new Dictionary<int, Dictionary<int, Coordinate>>();
                    zCoordinates = new Dictionary<int, Coordinate>();
                    zCoordinates.Add(c.Z, c);
                    yCoordinates.Add(c.Y, zCoordinates);
                    starCoordinateIndex.Add(c.X, yCoordinates);
                }
                else
                {
                    yCoordinates = starCoordinateIndex[c.X];
                    if (!yCoordinates.ContainsKey(c.Y))
                    {
                        zCoordinates = new Dictionary<int, Coordinate>();
                        zCoordinates.Add(c.Z, c);
                        yCoordinates.Add(c.Y, zCoordinates);
                    }
                    else
                    {
                        zCoordinates = yCoordinates[c.Y];
                        if (!zCoordinates.ContainsKey(c.Z))
                        {
                            zCoordinates.Add(c.Z, c);
                        }
                    }
                }
            }
        }

    }

    //Metoda koja kreira zvezde, planete i resurse;
    public static void CreateStars_()
    {
        if (null != starCoordinateIndex && starCoordinateIndex.Count > 0)
        {
            stars = new List<Star>();

            Random rPlanetCount = new Random(DateTime.Now.Millisecond);
            Random rResourceCount = new Random(DateTime.Now.Second);
            Random rResourceType = new Random();

            int planetCount = 0;
            int resourceCount = 0;
            int resourceType = 0;

            Star s = null;
            Planet p = null;
            Resource r = null;

            foreach (Coordinate c in starCoordinates.Values)
            {
                s = new Star();
                planetCount = rPlanetCount.Next(MinPlanetPerStar, MaxPlanetPerStar + 1);

                for (int i = 0; i < planetCount; i++)
                {
                    p = new Planet();
                    resourceCount = rResourceCount.Next(MinResourcePerPlanet, MaxResourcePerPlanet + 1);
                    string resources = "";
                    for (int j = 0; j < resourceCount; j++)
                    {
                        //r = new Resource(rResourceType.Next(0, 4), ResourceAmount);
                        //p.AddResource(r);
                        if (j > 0)
                        {
                            resources += ";";
                        }
                        resources += rResourceType.Next(0, 4).ToString();
                    }
                    //p.Resources = resources;
                    if (i > 0)
                    {
                        s.Planets += "|";
                    }
                    s.Planets += resources;
                    //s.AddPlanet(p);
                }
                c.AddObject(s);
            }
        }
    }

    public static string GetRangeData_(int x, int y, int z, int r)
    {
        string ret = "";

        int minX = x - r;
        int maxX = x + r;
        if (minX < 0)
        {
            minX = 0;
        }
        if (maxX > MaxX)
        {
            maxX = MaxX;
        }

        int minY = y - r;
        int maxY = y + r;
        if(minY < 0)
        {
            minY = 0;
        }
        if (maxY > MaxY)
        {
            maxY = MaxY;
        }

        int minZ = z - r;
        int maxZ = z + r;
        if(minZ < 0)
        {
            minZ = 0;
        }
        if(maxZ > MaxZ)
        {
            maxZ = MaxZ;
        }

        Dictionary<int, Dictionary<int, Coordinate>> yCoordinates = null;
        Dictionary<int, Coordinate> zCoordinates = null;
        Coordinate c = null;

        for (int i = minX; i <= maxX; i++)
        {
            if(starCoordinateIndex.ContainsKey(i))
            {
                yCoordinates = starCoordinateIndex[i];

                for (int j = minY; j <= maxY; j++)
                {
                    if (yCoordinates.ContainsKey(j))
                    {
                        zCoordinates = yCoordinates[j];

                        for (int k = minZ; k <= maxZ; k++)
                        {
                            if(zCoordinates.ContainsKey(k))
                            {
                                c = zCoordinates[k];

                                if("" != ret)
                                {
                                    ret += "!";
                                }

                                ret += c.ToString();
                                ret += "&";
                                for (int d = 0; d < c.Content.Count; d++)
                                {
                                    ret += c.Content[d].ToString();
                                    if (d < c.Content.Count - 1)
                                    {
                                        ret += "~";
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        return ret;
    }

    #endregion

    #region Users

    // Lista korisnika 
    private static Dictionary<string, User> users = null;

    /////////////////////////////////////////////////////////////////////////////////////////

    // Dodaj novog korisnika
    public static void AddUser_(string userName, string password)
    {
        if(null == users)
        {
            users = new Dictionary<string, User>();
        }

        users.Add(userName, new User(userName, password));
    }

    // Proveri da li korisnicko ime vec postoji
    public static bool ContainsUserName_(string userName)
    {
        if (null == users)
        {
            return false;
        }
        else
        {
            return users.ContainsKey(userName);
        }
    }

    #endregion

    #endregion

    #region Construction

    public Service()
    {

        //Uncomment the following line if using designed components 
        //InitializeComponent(); 
    }

    #endregion

    #region Web Methods

    #region Test

    [WebMethod]
    public string HelloWorld()
    {
        return "Hello World";
    }

    [WebMethod]
    public bool IsSpaceInitialised()
    {
        return IsSpaceInitialised_();
    }

    #endregion

    #region Space

    [WebMethod]
    public void CreateCoordinates(int maxX, int maxY, int maxZ, int count)
    {
        CreateStarCoordinates(maxX, maxY, maxZ, count);
    }

    [WebMethod]
    public void CreateStarsIndex()
    {
        CreateStarCoordinateIndex();
    }

    [WebMethod]
    public void CreateStars()
    {
        CreateStars_();
    }

    [WebMethod]
    public int GetStarCount()
    {
        return stars.Count;
    }

    [WebMethod]
    public string GetRangeData(int x, int y, int z, int r)
    {
        return GetRangeData_(x,y,z,r);
    }

    #endregion

    #region Users

    [WebMethod]
    public void AddUser(string userName, string password)
    {
        AddUser_(userName, password);
    }

    [WebMethod]
    public bool ContainsUserName(string userName)
    {
        return ContainsUserName_(userName);
    }

    [WebMethod]
    public int UsersCount()
    {
        return users.Count;
    }

    #endregion

    #endregion
}
